﻿using System;
using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Threading;
using Contracts;
using System.Linq;
using System.Threading;
using System.Windows.Interop;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using WpfAppHost.TimedQueue;

namespace WpfAppHost
{
    /// <summary>
    /// Interaction logic for MainAppWindow.xaml
    /// </summary>p
    [Export("MainWindow", typeof(System.Windows.Window))]
    [WpfHost]
    public partial class MainAppWindow : ApplicationWindow, IWpfHost
    {
        private TimedQueue<StatusMessage> statuses;
        private EventHandler StatusUpdatedEventHandler;
        
        public MainAppWindow()
        {
            InitializeComponent();

            statuses = new TimedQueue<StatusMessage>(5000, 20000);
            statuses.ItemAvailableEvent += 
                new EventHandler<ItemAvailableEventArgs<StatusMessage>>(statuses_ItemAvailableEvent);
            statuses.Start();

            StatusUpdatedEventHandler = new EventHandler(Addin_StatusUpdated);

            this.ApplicationName = "MEF Utility Runner";
            this.TrayIcon = Properties.Resources.Gear;
            this.HideOnClose = true;
        }

        [Import("AddinManager")]
        public AddinManager AddinManager
        {
            get;
            set;
        }

        public void Init()
        {
            this.AddinManager.Init();

            foreach (IWpfService addin in this.AddinManager.Addins)
            {
                try
                {
                    // Extra steps for administrative addins
                    if (addin is IWpfServiceAdmin)
                    {
                        (addin as IWpfServiceAdmin).ServiceHost = this;
                    }

                    // Main window needs to see all status updates
                    addin.StatusUpdated += StatusUpdatedEventHandler;

                    // Settings menu item on or off, ShowApp menu item on or off, Wire up callbacks, etc.
                    addin.Start();
                }
                catch (Exception x)
                {
                    ShowNonModalMessage("MEF Utility Runner", "Error starting " + addin.Name + " addin: " + x.Message);
                }
            }

            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Filter = "*.showme";
            watcher.Path = AddinManager.AddinsDir;
            watcher.Created += new FileSystemEventHandler(watcher_Created);
            watcher.EnableRaisingEvents = true;

            // Main list of addins
            addinListBox.ItemsSource = AddinManager.Addins;
        }

        void watcher_Created(object sender, FileSystemEventArgs e)
        {
            // Safeguard delete with delay to ensure other instance has closed it
            try
            {
                Thread.Sleep(1000);
                File.Delete(e.FullPath);
            }
            catch { }
            
            Dispatcher.BeginInvoke((ThreadStart)delegate() { this.ShowWindow(); }, DispatcherPriority.Background);
        }

        void statuses_ItemAvailableEvent(object sender, ItemAvailableEventArgs<StatusMessage> e)
        {
            Dispatcher.BeginInvoke((ThreadStart)delegate() { StatusUpdatedHandler(e.Item); }, DispatcherPriority.Background);
        }

        /// <summary>
        /// Handles status message from a plugin.  This is added to the queue of status items to show
        /// </summary>
        void Addin_StatusUpdated(object sender, EventArgs e)
        {
            IWpfService svc = sender as IWpfService;
            ShowNonModalMessage(svc.Name, svc.Status);
        }

        /// <summary>
        /// Handles status updates on the UI thread by showing a balloon
        /// </summary>
        void StatusUpdatedHandler(StatusMessage msg)
        {
            if (msg == null) throw new ArgumentException("cannot be NULL", "msg");

            this.ShowBalloonMessage(msg.SourceName, msg.Message);
        }

        public void ShowNonModalMessage(string msg)
        {
            statuses.AddItem(new StatusMessage("Unknown Addin", msg));
        }

        public void ShowNonModalMessage(string name, string msg)
        {
            statuses.AddItem(new StatusMessage(name, msg));
        }
    }

    public class StatusMessage
    {
        public StatusMessage(string name, string message)
        {
            this.SourceName = name;
            this.Message = message;
        }

        public string SourceName { get; set; }
        public string Message { get; set; }
    }

}
